﻿using System;
using System.Configuration;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Newtonsoft.Json.Serialization;
using Serilog;
using Sustainalytics.ESGRatings.Computing.Service.Helpers;
using Sustainalytics.ESGRatings.DataContract;

namespace Sustainalytics.ESGRatings.Computing.Service.Infrastructure
{
    /// <summary>
    /// If present a config section in app.config with a valid set id
    /// the associated temporary dataset will be uploaded from the database
    /// that includes:
    /// weights
    /// scores
    /// Ref universes
    /// Company Attributes: company type and template type
    /// on start up  goes to MongoDatabase and gets all available data
    /// </summary>
    public class ESGDataSource
    {
        private readonly string _httpLocalhostESGComputingService;

        private ESGDataSource()
        {
            var hostUrl = ConfigurationManager.AppSettings["httpHostUrl"];
            _httpLocalhostESGComputingService = hostUrl + "/api/v1/dataprovisioning/esgsets";
        }

        public static ESGDataSource GetInstance()
        {
            var localInstance = new ESGDataSource();

            return localInstance;
        }

        public async Task LoadDataFromDB()
        {
            try
            {
                var configForSelfCare = GetServiceAutoProvisioningConfiguration();

                if (configForSelfCare == null)
                {
                    throw new ArgumentNullException(nameof(configForSelfCare));
                }
                Guid? setId = null;

                if (!configForSelfCare.GetLatestSet)
                {
                    setId = configForSelfCare.SetId;
                }

                await PostDataAsync(setId).ConfigureAwait(false);
                Log.Debug("Self provisioning successful!");
            }
            catch (Exception e)
            {
                Log.Error(e, "");
            }
        }

        public async Task SwithchSet(Guid[] deletableSets, Guid? activeSetId)
        {
            if (activeSetId.HasValue)
            {
                if (await SetActiveSetAsync(activeSetId))
                    if (deletableSets.Length > 0 && !deletableSets.Contains(activeSetId.Value))
                    {
                        await DeleteSetsAsync(deletableSets);
                    }
            }
        }

        private static ServiceAutoProvisioningSection GetServiceAutoProvisioningConfiguration()
        {
            var config = ConfigurationManager.GetSection("ServiceAutoProvisioningGroup/ServiceAutoProvisioning");
            var configForSelfCare = config as ServiceAutoProvisioningSection;
            return configForSelfCare;
        }

        private async Task PostDataAsync(Guid? computationSetId)
        {
            using (var httpClient = new HttpClient { Timeout = new TimeSpan(0, 0, 30, 0) })
            {
                var jsonMediaTypeFormatter = new JsonMediaTypeFormatter
                {
                    SerializerSettings = { ContractResolver = new CamelCasePropertyNamesContractResolver() }
                };

                var result = await httpClient.PutAsync(this._httpLocalhostESGComputingService, new ESGDataContainerDTO { setId = computationSetId.GetValueOrDefault(), isActive = true }, jsonMediaTypeFormatter).ConfigureAwait(false);

                if (result.IsSuccessStatusCode)
                {
                    var insertedGuid = await result.Content.ReadAsAsync<Guid>(new[] { jsonMediaTypeFormatter }).ConfigureAwait(false);
                    if (insertedGuid == Guid.Empty)
                    {
                        throw new Exception();
                    }
                }
                else
                {
                    throw new Exception();
                }
            }
        }

        private async Task<bool> DeleteSetsAsync(Guid[] computationSetIds)

        {
            var builder = new UriBuilder(_httpLocalhostESGComputingService);
            var query = HttpUtility.ParseQueryString(builder.Query);
            var result = true;

            using (var httpClient = new HttpClient { Timeout = new TimeSpan(0, 0, 10, 0) })
            {
                foreach (var setId in computationSetIds)
                {
                    query["setId"] = setId.ToString();
                    builder.Query = query.ToString();
                    var url = builder.ToString();


                    var queryResult = await httpClient.DeleteAsync(url).ConfigureAwait(false);

                    result = result && queryResult.IsSuccessStatusCode;

                }
            }

            return result;
        }

        private async Task<bool> SetActiveSetAsync(Guid? activeSetId)
        {
            if (activeSetId.HasValue)
            {
                var request = new HttpRequestMessage(new HttpMethod("PATCH"), new Uri(_httpLocalhostESGComputingService))
                {
                    Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(new ESGDataContainerDTO { setId = activeSetId.Value, isActive = true }), Encoding.UTF8, "application/json")
                };

                using (var httpClient = new HttpClient { Timeout = new TimeSpan(0, 0, 10, 0) })
                {
                    var response = await httpClient.SendAsync(request).ConfigureAwait(false);

                    return response.IsSuccessStatusCode;

                }
            }

            return true;
        }

    }
}